package jmine.tec.web.front.pages.requests;

import static java.util.Collections.emptyList;
import static jmine.tec.web.wicket.spring.SpringBeanReference.forName;

import java.io.Serializable;
import java.util.List;

import jmine.tec.report.impl.table.ReportTableBuilder;
import jmine.tec.web.front.FrontException;
import jmine.tec.web.front.FrontMessages;
import jmine.tec.web.front.dao.BackOfficeRequestDAO;
import jmine.tec.web.front.dao.BackOfficeRequestStatusDAO;
import jmine.tec.web.front.dao.BackOfficeRequestTypeDAO;
import jmine.tec.web.front.domain.BackOfficeRequest;
import jmine.tec.web.front.domain.BackOfficeRequestProperty;
import jmine.tec.web.front.domain.BackOfficeRequestPropertyBigDecimal;
import jmine.tec.web.front.domain.BackOfficeRequestPropertyDate;
import jmine.tec.web.front.domain.BackOfficeRequestPropertyString;
import jmine.tec.web.front.domain.BackOfficeRequestStatus;
import jmine.tec.web.front.domain.BackOfficeRequestType;
import jmine.tec.web.front.domain.BackOfficeRequestValue;
import jmine.tec.web.front.domain.BackOfficeRequestValueBigDecimal;
import jmine.tec.web.front.domain.BackOfficeRequestValueDate;
import jmine.tec.web.front.domain.BackOfficeRequestValueString;
import jmine.tec.web.front.forms.FormMetadata;
import jmine.tec.web.front.pages.requests.filter.BackOfficePropertyPanelFactory;
import jmine.tec.web.front.pages.requests.filter.BackOfficeRequestFilter;
import jmine.tec.web.front.pages.requests.filter.BackOfficeRequestPropertyPanel;
import jmine.tec.web.wicket.BeanReference;
import jmine.tec.web.wicket.component.command.img.ImageCommand;
import jmine.tec.web.wicket.component.command.img.ViewCommand;
import jmine.tec.web.wicket.component.command.img.ViewCommandHandler;
import jmine.tec.web.wicket.pages.form.ListPage;
import jmine.tec.web.wicket.spring.SpringBeanReference;

import org.apache.wicket.Page;
import org.apache.wicket.PageParameters;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.form.DropDownChoice;
import org.hibernate.Hibernate;

import bancosys.tec.exception.MessageCreator;
import bancosys.tec.persist.dao.BaseDAOFactory;
import bancosys.tec.persist.dao.BeanNotFoundException;
import bancosys.tec.security.annotation.Secure;
import bancosys.tec.security.authorization.UrlPermission;
import bancosys.tec.utils.date.Clock;

/**
 * Page that lists back office requests
 * 
 * @author lundberg
 */
@Secure(id = "URL_BACK_OFFICE_REQUEST_LIST", permissionType = UrlPermission.class)
public class BackOfficeRequestListPage extends ListPage<BackOfficeRequestFilter, BackOfficeRequest> implements ViewCommandHandler {

    /**
     * {@inheritDoc}
     */
    public List<BackOfficeRequest> search(BaseDAOFactory daoFactory) {
        BackOfficeRequestFilter m = this.getModel();
        if (m.getType() == null || m.getDate() == null) {
            return emptyList();
        }

        BeanReference<BackOfficeRequestDAO> backOfficeRequestDAO = forName("backOfficeRequestDAO");
        return backOfficeRequestDAO.get().findByTypeDateStatusUserProperties(m.getType(), m.getDate(), m.getStatus(),
                m.getRequestingUser(), m.getPropertyValues());
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected BackOfficeRequestFilter createModel() {
        BeanReference<Clock> clock = forName("wallClock");
        BeanReference<BackOfficeRequestTypeDAO> backOfficeRequestTypeDAO = forName("backOfficeRequestTypeDAO");
        BackOfficeRequestFilter filter = new BackOfficeRequestFilter();
        filter.setDate(clock.get().currentDate());
        filter.setType(backOfficeRequestTypeDAO.get().findAllOrderedByNk().get(0));
        return filter;
    }

    /**
     * Load search filters
     */
    protected void loadFilters() {
        this.getModel().clearPropertyValues();
        for (BackOfficeRequestProperty property : this.getModel().getType().properties()) {
            BackOfficeRequestValue<?> value = null;

            if (Hibernate.getClass(property).equals(BackOfficeRequestPropertyString.class)) {
                value = new BackOfficeRequestValueString();
            } else if (Hibernate.getClass(property).equals(BackOfficeRequestPropertyBigDecimal.class)) {
                value = new BackOfficeRequestValueBigDecimal();
            } else if (Hibernate.getClass(property).equals(BackOfficeRequestPropertyDate.class)) {
                value = new BackOfficeRequestValueDate();
            }

            value.setProperty(property);
            this.getModel().addPropertyValue(value);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void addSearchFields(final WebMarkupContainer container) {
        DropDownChoice<BackOfficeRequestType> type = new DropDownChoice<BackOfficeRequestType>("type", this.findAvailableRequestTypes()) {
            @Override
            protected boolean wantOnSelectionChangedNotifications() {
                return true;
            }

            @Override
            protected void onSelectionChanged(BackOfficeRequestType newSelection) {
                BackOfficeRequestFilter model = BackOfficeRequestListPage.this.getModel();
                BeanReference<BackOfficeRequestTypeDAO> backOfficeRequestTypeDAO = forName("backOfficeRequestTypeDAO");

                try {
                    BackOfficeRequestType reloadedType = backOfficeRequestTypeDAO.get().findByPk(model.getType().getPk());
                    model.setType(reloadedType);
                } catch (BeanNotFoundException e) {
                    throw new FrontException(FrontMessages.REQUEST_TYPE_NOT_FOUND.create());
                }

                BackOfficeRequestListPage.this.loadFiltersPanel(container);
                BackOfficeRequestListPage.this.generateTable();
            }
        };

        type.setNullValid(false);
        container.add(type);
        container.add(this.createDateField("date", true));
        DropDownChoice<BackOfficeRequestStatus> status = this.createDropDown("status", this.findAvailableRequestStatus());
        status.setNullValid(true);
        container.add(status);
        container.add(this.createTextField("requestingUser"));

        this.loadFiltersPanel(container);
    }

    /**
     * Load the request type property filters
     * 
     * @param container container to save the panel
     */
    private void loadFiltersPanel(final WebMarkupContainer container) {
        if (this.getModel().getType() != null) {
            this.loadFilters();
            FormMetadata typeMetadata = SpringBeanReference.<FormMetadata> forName(this.getModel().getType().getMetadata()).get();
            BackOfficePropertyPanelFactory propertyPanelFactory = typeMetadata.getPropertyPanelFactory();
            BackOfficeRequestPropertyPanel panel = propertyPanelFactory.createPanel("typePropertyPanel", this.getModel());
            container.addOrReplace(panel);
        }
    }

    /**
     * Finds the default value for request type
     * 
     * @return list
     */
    private List<BackOfficeRequestType> findAvailableRequestTypes() {
        BeanReference<BackOfficeRequestTypeDAO> backOfficeRequestTypeDAO = forName("backOfficeRequestTypeDAO");
        return backOfficeRequestTypeDAO.get().findAllOrderedByNk();
    }

    /**
     * Finds the default value for request status
     * 
     * @return list
     */
    private List<BackOfficeRequestStatus> findAvailableRequestStatus() {
        BeanReference<BackOfficeRequestStatusDAO> backOfficeRequestTypeDAO = forName("backOfficeRequestStatusDAO");
        return backOfficeRequestTypeDAO.get().findAllOrderedByNk();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void addResultTableColumns(ReportTableBuilder<BackOfficeRequest> table) {
        table.addTimestampColumn("requestTimestamp", "Data/Hora", "requestTimestamp");
        table.addStringColumn("requestingUser", "Usuário", "requestingUser");
        table.addStringColumn("status", "Status", "status");
        if (this.getModel().getType() != null) {
            for (BackOfficeRequestProperty property : this.getModel().getType().properties()) {
                property.setUpReportColumn(table);
            }
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected MessageCreator getHelpTextCreator() {
        return FrontMessages.REQUEST_PAGE_HELP_TEXT;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public List<ImageCommand> getTableCommands(BackOfficeRequest entity) {
        List<ImageCommand> commands = super.getTableCommands(entity);
        commands.add(new ViewCommand(this));
        return commands;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean shouldIncludeTableCommands() {
        return true;
    }

    /**
     * {@inheritDoc}
     */
    public Page createViewPage(Serializable entityPk) {
        PageParameters parameters = new PageParameters();
        parameters.add("id", entityPk.toString());
        return new BackOfficeRequestViewPage(this, parameters);
    }
}
